package cheme.ProcessEditor.Parts;

import java.beans.PropertyChangeEvent;
import java.util.List;

import org.eclipse.draw2d.ChopboxAnchor;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.MouseEvent;
import org.eclipse.draw2d.MouseListener;
import org.eclipse.draw2d.XYAnchor;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.NodeEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.requests.CreateConnectionRequest;
import org.eclipse.gef.requests.ReconnectRequest;

import cheme.ProcessEditor.Figures.ProcessUnitFig;
import cheme.ProcessEditor.Policies.ChemeGraphicalNodePolicy;
import cheme.ProcessEditor.Policies.ContainerHighlightEditPolicy;
import cheme.ProcessEditor.Policies.FigureDropPolicy;
import cheme.ProcessEditor.Policies.ProcessModelLayoutPolicy;
import cheme.ProcessEditor.Policies.ProcessUnitPolicy;
import cheme.ProcessModel.ProcessUnits.ProcessUnit;


public class ProcessUnitPart extends PropertyAwarePart implements NodeEditPart, INonResizablePart
{
	public ProcessUnit getModel()
	{
		return (ProcessUnit)super.getModel();
	}
	
	public ProcessUnitFig getFigure()
	{
		return (ProcessUnitFig)super.getFigure();
	}

	/*
	 * For now, just send back a simple label representing the model element's
	 * text data.
	 */
	@Override
	protected IFigure createFigure()
	{
		IFigure fig =  createFigureInternal();
		fig.addMouseListener(new MouseListener()
		{
			public void mouseDoubleClicked(MouseEvent me)
			{	
			}

			public void mousePressed(MouseEvent me)
			{
			}

			public void mouseReleased(MouseEvent me)
			{
				System.out.println("mouseReleased");
			}
		});
		
		return fig;
	}

	protected IFigure createFigureInternal()
	{
		return new ProcessUnitFig();
	}
	
	/*
	 * Edit policies will control how GUI level event such as mouse clicks s and
	 * key presses are translated into commands enacted on the model. For now we
	 * have no interaction and so do not define any edit policies.
	 */
	@Override
	protected void createEditPolicies()
	{
		installEditPolicy(EditPolicy.COMPONENT_ROLE, new ProcessUnitPolicy());
		installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new ChemeGraphicalNodePolicy());
		installEditPolicy(EditPolicy.SELECTION_FEEDBACK_ROLE, new ContainerHighlightEditPolicy());
		
		installEditPolicy(EditPolicy.LAYOUT_ROLE, new FigureDropPolicy());
	}

	@Override
	protected void refreshVisuals()
	{
		Point loc = getModel().getLocation();
		Dimension size= getFigure().getPreferredSize();//getModel().getSize();
		Rectangle r = new Rectangle(loc ,size);

		((GraphicalEditPart)getParent()).setLayoutConstraint(this, getFigure(), r);
	}
	
	@Override
	protected void handleTextChange(PropertyChangeEvent evt)
	{
		//getProcessUnitFig().setText(getProcesssUnit().getText());
		getFigure().revalidate();
		super.handleTextChange(evt);
	}
	
	@Override
	protected void handleBoundsChange(PropertyChangeEvent evt)
	{
		refreshVisuals();
		super.handleBoundsChange(evt);
	}

	/* 
	 * Return objects which represent the points to which connections between
	 * nodes can be attached. Specifically, this gives anchor points to existing 
	 * connections and should always be allowed.
	 */
	public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connection)
	{
		return new ChopboxAnchor(getFigure());
	}

	/*
	 * Return objects which represent the points to which connections between 
	 * nodes can be attached. Specifically, this gives anchor points to existing 
	 * connections and should always be allowed.
	 */
	public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connection)
	{
		return new ChopboxAnchor(getFigure());
	}

	/*
	 * If this units threshold has been surpassed, reject new anchors.
	 */
	/*
	 * Problem, rejecting an anchor... giving back an XY rather than Chopbox,
	 * means that the connection resolves to some point in the middle of he figure...
	 * the default imple relies on both anchors giving when the cursor is inside a figure 
	 * to resolve to the same chopbox based point.
	 * 
	 * How to fix?
	 * 
	 * Well, we are talking about draing a line from within the figure to within 
	 * the figure ... so say, if he source is me, give a chopbox--effectively 
	 * hiding the connection, else, give a XY.
	 */
	public ConnectionAnchor getSourceConnectionAnchor(Request request)
	{
		ConnectionAnchor anchor = null;
		try
		{
			EditPart source = null;
			Point location = null;
			
			if(request instanceof CreateConnectionRequest)
			{
				CreateConnectionRequest createReq = (CreateConnectionRequest)request;
				source = createReq.getSourceEditPart();
				location = createReq.getLocation();
			}
			else if(request instanceof ReconnectRequest)
			{
				ReconnectRequest reconnectReq = (ReconnectRequest)request;
				source = reconnectReq.getConnectionEditPart().getSource();
				location = reconnectReq.getLocation();
			}
			
			/*
			 * Always return a chopbox anchor if the cursor is within the bounds of the originating figure.
			 * Also, if this is not the connection originating figure and it can accept the connection do that chop box thang.
			 */
			
			if(source == this || getModel().willAcceptOutStream())
			{
				anchor = new ChopboxAnchor(getFigure());
			}
			else
			{
				anchor = new XYAnchor(location);
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}

		return anchor;
	}

	/*
	 * If this units threshold has been surpassed, reject new anchors.
	 */
	public ConnectionAnchor getTargetConnectionAnchor(Request request)
	{
		ConnectionAnchor anchor = null;
		try
		{
			EditPart source = null;
			Point location = null;
			
			if(request instanceof CreateConnectionRequest)
			{
				CreateConnectionRequest createReq = (CreateConnectionRequest)request;
				source = createReq.getSourceEditPart();
				location = createReq.getLocation();
			}
			else if(request instanceof ReconnectRequest)
			{
				ReconnectRequest reconnectReq = (ReconnectRequest)request;
				source = reconnectReq.getConnectionEditPart().getSource();
				location = reconnectReq.getLocation();
			}
			
			/*
			 * Always return a chopbox anchor if the cursor is within the bounds of the originating figure.
			 * Also, if this is not the connection originating figure and it can accept the connection do that chop box thang.
			 */
			
			if(source == this || getModel().willAcceptInStream())
			{
				anchor = new ChopboxAnchor(getFigure());
			}
			else
			{
				anchor = new XYAnchor(location);
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}

		return anchor;
	}

	protected List getModelSourceConnections()
	{
		return getModel().getOutStreams();
	}

	protected List getModelTargetConnections()
	{
		return getModel().getInStreams();
	}
	
	@Override
	public void setParent(EditPart parent)
	{
		super.setParent(parent);
	}
}
